package socketTransmission;

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SocketConnectionPool{

	private int i_SocketNumber = 50;
	private int i_Length = 10;
	private List<Socket> socketList = new ArrayList<Socket>();
	private List<Socket> socketListOriginal = new ArrayList<Socket>();
	private List<String> stringList = new ArrayList<String>();
	private Map<Socket,SocketConnection> socketConnectionMap = new HashMap<Socket,SocketConnection>();
	private int i_QueueEnd = 0;
	private List<Long> waitTime = new ArrayList<Long>();
	
	public List<Long> getWaitTime() {
		return waitTime;
	}

	public void setWaitTime(List<Long> waitTime) {
		this.waitTime = waitTime;
	}

	SocketConnectionPool(){
		i_QueueEnd = i_SocketNumber-1;
		for(int i=0;i<i_Length;i++){
			String temp = Integer.toString(i);
			stringList.add(i,temp);
		}
	}
	
	SocketConnectionPool(String serverIP,int serverPort){
		
		initiateSocketConnection(serverIP,serverPort);
	}
	
	public synchronized String get(){
		
		while(i_QueueEnd < 0){
			try{
				wait();
			}catch(InterruptedException e){
				e.printStackTrace();
				throw new RuntimeException("Error wiat() in get()...",e);
			}
		}
		String temp = stringList.get(i_QueueEnd);
		System.out.println("Get> "+i_QueueEnd+" > "+temp);
		i_QueueEnd--;
		
		return temp;
		
	}
	
	public synchronized void put(String returnString){
		i_QueueEnd++;
		stringList.add(i_QueueEnd,returnString);
		notify();
		System.out.println("Put> "+i_QueueEnd+" > "+returnString);
	}
	
	//get a socket from socket pool
	public synchronized Socket getSocket(){
		
		while(i_QueueEnd < 0){
			try{
				long initTime = System.currentTimeMillis();
				wait();
				long endTime = System.currentTimeMillis();
				waitTime.add(endTime-initTime);
				
			}catch(InterruptedException e){
				e.printStackTrace();
				throw new RuntimeException("Error wiat() in getSocket...",e);
			}
		}
		Socket client = socketList.get(i_QueueEnd);
		//System.out.println("Get> "+i_QueueEnd+" > "+client);
		i_QueueEnd--;
		return client;	
	}
	
	public synchronized SocketConnection getConnection(Socket socket){
		SocketConnection socketConnection = socketConnectionMap.get(socket);
		return socketConnection;
	}
	//return the socket to the socket pool
	public synchronized void returnSocket(Socket returnSocket){
		i_QueueEnd++;
		socketList.add(i_QueueEnd, returnSocket);	
		notify();
		//System.out.println("Put> "+i_QueueEnd+" > "+returnSocket);
	}
	
	//initialization of the SocketConnection
	private synchronized void initiateSocketConnection(String serverIP,int serverPort){
		
		i_QueueEnd = i_SocketNumber-1;
		for(int i=0;i<i_SocketNumber;i++){
			try{
				
				Socket client = new Socket(serverIP, serverPort);
				socketList.add(i,client);
				socketListOriginal.add(i,client);
				SocketConnection socketConnection = new SocketConnection(client);
				socketConnectionMap.put(client, socketConnection);
				
			}catch(IOException e){
				e.printStackTrace();
				throw new RuntimeException("Error connecting to the server",
						e);
			}
		}
		System.out.println("Connected to " + serverIP + " in port: "
				+ serverPort);
	}
	
	//close all the connection,the socketListOriginal save all the original socket.
	//so all the used socket can be closed correctly.
	public synchronized void destroy(){
		
		for(int i=0;i<i_SocketNumber;i++){
			
			Socket socket = socketListOriginal.get(i);
			SocketConnection socketConnecion = socketConnectionMap.get(socket);
			socketConnecion.closeConnection();		
		}
		System.out.println("ClientConnectionPool has been closed");
	}
	

}
